package com.taobao.server;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.binary.Base64;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.taobao.api.TaobaoApiException;
import com.taobao.api.direct.TaobaoDirectJsonRestClient;
import com.taobao.api.model.Item;
import com.taobao.api.model.ItemsGetRequest;
import com.taobao.api.model.ItemsGetResponse;
import com.taobao.api.model.Refund;
import com.taobao.api.model.RefundGetRequest;
import com.taobao.api.model.RefundGetResponse;
import com.taobao.api.model.RefundsApplyGetRequest;
import com.taobao.api.model.RefundsApplyGetResponse;
import com.taobao.api.model.RefundsRecieveGetRequest;
import com.taobao.api.model.RefundsRecieveGetResponse;
import com.taobao.api.model.Sku;
import com.taobao.api.model.TaobaoResponse;
import com.taobao.api.model.TradeGetRequest;
import com.taobao.api.model.TradeGetResponse;
import com.taobao.client.UpperService;
import com.taobao.client.obj.TopItem;
import com.taobao.client.obj.TopRefund;
import com.taobao.client.obj.TopSku;
import com.taobao.client.obj.TopTadget;
import com.taobao.client.obj.TopTrade;

/**
 * The server side implementation of the RPC service.
 * 
 * @author jiangyongyuan@use.com.cn
 * 
 */
@SuppressWarnings("serial")
public class UpperServiceImpl extends RemoteServiceServlet implements
		UpperService {

	// System parameters
	private String testUrl;
	private String appkey;
	private String secret;
	private String loginAddress;
	// A client object
	private TaobaoDirectJsonRestClient client;
	// Service to handle the trade-about
	private TradeService tradeService;

	/**
	 * @param nick
	 * @return A list of top items
	 * @throws
	 */
	public List<TopItem> itemsGet(String nick) throws Exception {
		String ITEMS_GET_FIELDS_STRING = "iid,title,nick,type,cid,pic_path,delist_time,price,post_fee,sku";
		ItemsGetRequest itemGetRequest = new ItemsGetRequest();
		itemGetRequest.setFields(ITEMS_GET_FIELDS_STRING);
		itemGetRequest.setNicks(nick);
		try {
			ItemsGetResponse itemsGet = client.itemsGet(itemGetRequest);
			processError(itemsGet);

			List<Item> items = itemsGet.getItems();
			List<TopItem> top = new ArrayList<TopItem>();

			if (items == null || items.size() < 0)
				return top;

			for (Item i : items) {
				TopItem t = new TopItem();
				List<Sku> skus = i.getSkus();
				List<TopSku> ks = new ArrayList<TopSku>();

				if (skus != null) {
					for (Sku s : skus) {
						TopSku sk = new TopSku();
						sk.skuId = s.getSkuId();
						sk.price = s.getPrice();
						sk.quantity = s.getQuantity();
						ks.add(sk);
					}
				}
				t.iid = i.getIid();
				t.pic = i.getPicPath();
				t.price = i.getPrice();
				t.title = i.getTitle();
				t.topSku = ks;
				top.add(t);
			}
			return top;
		} catch (TaobaoApiException e) {
			throw new Exception(e.getMessage());
		}
	}

	/**
	 * @param url
	 * @param app
	 * @param secrt
	 * @param loginAddress
	 * @param getSessionAddress
	 * @return If initialize succeed, return true, or return false.
	 */
	@Override
	public boolean init(String url, String app, String secrt,
			String loginAddress) throws Exception {
		this.testUrl = url;
		this.appkey = app;
		this.secret = secrt;
		this.loginAddress = loginAddress;

		client = (TaobaoDirectJsonRestClient) getThreadLocalRequest()
				.getSession().getAttribute("TaobaoClient");
		try {
			if (client == null) {
				client = new TaobaoDirectJsonRestClient("300", testUrl, appkey,
						secret);
				getThreadLocalRequest().getSession().setAttribute(
						"TaobaoClient", client);
			}
			return true;
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * @param item
	 * @param buyer
	 * @param seller
	 */
	public void addTrade(List<TopItem> item, String buyer, String seller,
			String name, String phone, String mobile, String province,
			String city, String area, String division_code, String post_code,
			String address_detail, boolean isNewAddress, String memo,
			String discount) throws Exception {

		getTradeService().addTrade(item, buyer, seller, name, phone, mobile,
				province, city, area, division_code, post_code, address_detail,
				isNewAddress, memo, discount);
	}

	/**
	 * @param tid
	 */
	public String deliverySend(String tid) throws Exception {
		getTradeService().deliverySend(tid);
		return null;
	}

	/**
	 * @param nick
	 * @return A list of top trade
	 */
	public List<TopTrade> tradeSoldGet(String nick) throws Exception {
		return getTradeService().testTradesSoldGetByFields(getSession(),
				getLoginName());
	}

	/**
	 * @param userName
	 *            The user name
	 * @param password
	 *            The password
	 * @return The session id
	 * @throws
	 */
	@Override
	public String getSession(String userName, String password) throws Exception {
		// System.out.println("get session");
		// LoginUtil2 loginUtil = new LoginUtil2(loginAddress,
		// getSessionAddress,
		// appkey, userName, password);
		// String sessionId = loginUtil.getTopSession();
		//
		// if (sessionId != null && !sessionId.equals("")) {
		// getThreadLocalRequest().getSession().setAttribute("SESSION",
		// sessionId);
		// getThreadLocalRequest().getSession().setAttribute("NAME", userName);
		// return sessionId;
		// } else {
		// throw new Exception("Get Session Id Failed");
		// }
		return null;
	}

	public String getLoginURL(String domain, String url) {

//		String action = "post";
//		String isextshop = "true";
//		String from = "top";
//		String logourl = "true";
//		String forceLogin = "Y";
		String extShopDomain = domain;// 没用.只是用来获得uri
//		String Domain = "top";
		String extShopTitle = "top";
		String tg = url;

		StringBuffer buffer = new StringBuffer();
		buffer.append("api_key=" + appkey);
		buffer.append("&action=logon");
//		buffer.append("&isextshop=" + isextshop);
//		buffer.append("&from=" + from);
		buffer.append("&ext_shop_title=" + extShopTitle);
		buffer.append("&ext_shop_domain=" + extShopDomain);
//		buffer.append("&Domain=" + Domain);
		buffer.append("&callback_url=" + tg);

		return loginAddress + buffer.toString();
	}

	/**
	 * @param nick
	 *            The nickname of the buyer
	 */
	@Override
	public List<TopTrade> tradeBoughtGet(String nick) throws Exception {
		/**
		 * Because in method getSession attribute "NAME" is set already, so
		 * getLoginName() can return a value always.
		 */
		return getTradeService().tradeBoughtGet(getLoginName());
	}

	/**
	 * 
	 * @return The session id stored in the session object
	 */
	public String getSession() {
		Object attribute = getThreadLocalRequest().getSession().getAttribute(
				"SESSION");
		if (attribute == null)
			return "";
		return (String) attribute;
	}

	public String setSession(String session, String param) {
		try {
			param = URLDecoder.decode(param, "UTF8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		byte[] decodeBase64 = Base64.decodeBase64(param.getBytes());
		String redirectUrl = new String(decodeBase64);

		String name = extractParam(redirectUrl, "visitor_nick=");
		getThreadLocalRequest().getSession().setAttribute("SESSION", session);
		getThreadLocalRequest().getSession().setAttribute("NAME", name);
		return null;
	}

	/**
	 * 
	 * @param redirectUrl
	 * @param param
	 */
	private String extractParam(String redirectUrl, String param) {
		int index1 = redirectUrl.indexOf(param);
		if (index1 != -1) {
			index1 = index1 + param.length();
			int index2 = redirectUrl.indexOf('&', index1);
			if (index2 == -1) {
				index2 = redirectUrl.length();
			}
			return redirectUrl.substring(index1, index2);
		}
		return "not found in redirect url";
	}

	/**
	 * 
	 * @return The name of login user stored in the session
	 */
	public String getLoginName() {
		Object attribute = getThreadLocalRequest().getSession().getAttribute(
				"NAME");
		if (attribute == null)
			return "";
		return (String) attribute;
	}

	@Override
	public String getUrl(Map<String, String> params) throws Exception {
		params.put("nick", getLoginName());
		return (UrlMaker.getUrl(params, appkey, secret, getSession()));
	}

	/**
	 * 
	 * @param r
	 *            A response object
	 * @throws Exception
	 */
	public void processError(TaobaoResponse r) throws Exception {
		if (!r.isSuccess()) {
			System.err.println(r.getBody());
			throw new Exception(r.getErrorCode() + ":" + r.getMsg());
		}
	}

	/**
	 * 
	 * @return A service handling trades-about
	 */
	private TradeService getTradeService() {
		if (tradeService == null)
			tradeService = new TradeService(client, this);
		return tradeService;
	}

	/**
	 * Invoke the top api to get a list of refunds
	 * 
	 * @param nick
	 *            The nick name of the buyer
	 * @return A list of top refunds
	 */
	@Override
	public List<TopRefund> getBuyerRefunds(String nick) throws Exception {
		// A request object
		RefundsApplyGetRequest req = new RefundsApplyGetRequest();
		// Set fields
		req
				.setFields("refund_id,tid,oid,buyer_nick,order_status,status,good_status,refund_fee,address");
		// Must be independent_shop_trade
		req.setType(TradeService.TYPE);
		// Return a response object
		RefundsApplyGetResponse rsp = client.refundsApplyGet(req, getSession(),
				getLoginName());
		// Handle various errors
		processError(rsp);
		// Create a list of top refunds
		List<TopRefund> topRefundList = new ArrayList<TopRefund>();
		// A reference to a list of refunds
		List<Refund> refundList = rsp.getRefundList();
		// Copy data from refundList to topRefundList
		if (refundList != null) {
			// Iterate refundList
			for (Refund refund : refundList) {
				
				// CLOSE的退款不返回前端,因为退款有多条，退款关闭的不能进行处理：//CLOSED(退款关闭)
				String status = refund.getStatus();
				if ("CLOSE".equalsIgnoreCase(status)){
					continue;
				}
				
				// New a top refund object
				TopRefund topRefund = new TopRefund();

				RefundGetRequest r = new RefundGetRequest();
				r.setRefundId(refund.getRefundId());
				r.setFields("oid");
				RefundGetResponse refundGet = client.refundGet(r, getSession(),
						getLoginName());
				String oid = refundGet.getRefund().getOid();
				refund.setOid(oid);

				BeanUtils.copyProperties(topRefund, refund);
				topRefundList.add(topRefund);
			}
		}
		return topRefundList;
	}

	/**
	 * @param seller
	 *            the nick name of seller
	 */
	@Override
	public List<TopRefund> getSellerRefund(String seller) throws Exception {
		// TODO Auto-generated method stub
		// New a request object
		RefundsRecieveGetRequest req = new RefundsRecieveGetRequest();
		// Set fields
		req
				.setFields("refund_id,oid,tid,seller_nick,order_status,status,good_status");

		// Must be independent_shop_trade
		req.setType(TradeService.TYPE);
		// Return a response object
		RefundsRecieveGetResponse rsp = client.refundsRecieveGet(req,
				getSession(), getLoginName());

		// Handle various errors
		processError(rsp);

		// Create a list of top refunds
		List<TopRefund> topRefundList = new ArrayList<TopRefund>();

		// A reference to a list of refunds
		List<Refund> refundList = rsp.getRefundList();

		// Copy data from refundList to topRefundList
		if (refundList != null) {
			// Iterate refundList
			for (Refund refund : refundList) {

				// CLOSE的退款不返回前端,因为退款有多条，退款关闭的不能进行处理：//CLOSED(退款关闭)
				String status = refund.getStatus();
				if ("CLOSED".equalsIgnoreCase(status)){
					continue;
				}

				// New a top refund object
				TopRefund topRefund = new TopRefund();
				BeanUtils.copyProperties(topRefund, refund);

				System.out.println("UpperServiceImpll: tid" + refund.getTid()
						+ " oid = " + refund.getOid() + " refund id="
						+ refund.getRefundId()+" status="+refund.getStatus());
				topRefundList.add(topRefund);
			}
		}
		return topRefundList;
	}

	/**
	 * The user logout
	 * 
	 * @param url
	 *            the callback url
	 * @param domain
	 *            the domain
	 */
	public String logout(String domain, String url) {
		String action = "logoff";
//		String isextshop = "true";
		String tg = url;

		StringBuffer buffer = new StringBuffer();
		buffer.append("api_key=" + appkey);
		buffer.append("&action=" + action);
//		buffer.append("&isextshop=" + isextshop);
		buffer.append("&callback_url=" + tg);
		
		String extShopTitle = "top";
		
		buffer.append("&ext_shop_title=" + extShopTitle);
		buffer.append("&ext_shop_domain=" + domain);

		return loginAddress + buffer.toString();
	}

	/**
	 * 
	 */
	public TopRefund getRefundInfo(String refundId) throws Exception {
		RefundGetRequest req = new RefundGetRequest();
		req.setRefundId(refundId);
		req
				.setFields("refund_id,alipay_no,tid,oid,buyer_nick,seller_nick,total_fee,status,created,"
						+ "refund_fee,good_status,has_good_return,payment,reason,desc,iid,title,price,num,"
						+ "good_return_time,company_name,sid,address ");

		RefundGetResponse rsp = client.refundGet(req, getSession(),
				getLoginName());

		processError(rsp);

		if (rsp != null) {
			TopRefund tr = new TopRefund();
			BeanUtils.copyProperties(tr, rsp.getRefund());
			return tr;
		}
		return null;
	}

	
	/**
	 * Apply a sub appkey.
	 * @param parentKey the key of the parent application.
	 * @param pathName the path of the logo file.
	 * @return a toptadget object.
	 */
	public TopTadget applySubAppKey(String parentKey, String pathName) throws Exception {
//		
//		System.out.println("UpperServiceImpl::applySubAppKey");
//		
//		String appkey = "sns";
//		String secret = "sns";
//		String sessionNick = "tbtest5";
//		String testUrl = "http://192.168.212.189:8080/top/private/services/rest";
//		
////		TaobaoShopexRestClient shopExClient = new TaobaoShopexJsonRestClient(testUrl, appkey, secret);
//		try {
//			TaobaoShopexDirectRestClient shopExClient = new TaobaoShopexDirectJsonRestClient(testUrl, appkey, secret);
//			
//			SubappApplyRequest request = new SubappApplyRequest();
//			request.setParentAppKey("wudangniu");
//			// This title should differs each time this method is called.
//			int seq = 0;
//			request.setTitle("ShopEx Sub App 11" + seq++);
//			request.setCallbackUrl("http://localhost:8888/pageapi.html");
//			request.setServiceCode("TADGET_SHOP_TACTIC");
//			File file = new File(pathName);
//			
//			request.setLogo(new File(pathName));
//			
//			SubappApplyResponse response = shopExClient.subappApply(request, "xxx", sessionNick);
//	
//			processError(response);
//			
//			Tadget tadget = response.getTadget();
//	
//			TopTadget topTadget = new TopTadget();
//						
//			topTadget.setAppKey(tadget.getAppKey());
//			topTadget.setAppSecret(tadget.getAppSecret());
//			
//			System.out.println("AppKey:\t" + topTadget.getAppKey() + "AppSecret:\t" + topTadget.getAppSecret());
//			return topTadget;
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		return null;
	}		


	@Override
	public void addTradeMemo(String memo, String tid) throws Exception {
		getTradeService().addTradeMemo(memo, tid);
	}
	
	/**
	 * Get the full info the trade.
	 * 
	 * @param tid
	 * @throws Exception
	 */
	public TopTrade getTdFullInfo(String tid, String oid) throws Exception {
		// New a request object.
		TradeGetRequest req = new TradeGetRequest();

		// Set parameters.
		req.setFields("orders");
		req.setTid(tid);

		try {
			// Return a response object.
			TradeGetResponse rsp = client.tradeFullInfoGet(req, getSession(), getLoginName());
			
			processError(rsp);
			
			TopTrade topTrade = new TopTrade();
			
			System.out.println(rsp.getTrade().getOrders().get(0).getMemo());
			// Because we just need the memo information, so we don't use the BeanUtils.
			// We just put it in the buyerMemo property.
			topTrade.setBuyerMemo(rsp.getTrade().getOrders().get(0).getMemo());
			
		    return topTrade;
	    } catch (Exception e) {
	    	e.printStackTrace();
	    }
	    return null;
	}

}
